package dao.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import model.impl.network.StreetImpl;

import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.resotc.dao.LaneDAO;
import org.resotc.dao.StreetDAO;
import org.resotc.model.Lane;
import org.resotc.model.Street;

import com.google.inject.Inject;

public class StreetDAOImpl extends AbstractXMLDAO implements StreetDAO {

	private final static String indexFileName = "street.xml";
	private HashMap<Integer, Street> streets;
	private LaneDAO laneDAO;

	@Inject
	public StreetDAOImpl(LaneDAO laneDAO) throws JDOMException, IOException {
		this.laneDAO = laneDAO;
		indexFile = new File(rootPath + "/" + indexFileName);
		loadXML();
		parseXML();
	}

	/**
	 * @see StreetDAO#getStreets()
	 */
	public HashMap<Integer, Street> getStreets() {
		return streets;
	}

	/**
	 * @see StreetDAO#getStreet(int)
	 */
	public Street getStreet(int id) {
		return streets.get(id);
	}

	/**
	 * @see StreetDAO#createStreet(Street)
	 */
	public void createStreet(Street street) {
		createAndUpdateStreet(street);
	}

	/**
	 * @see StreetDAO#updateStreet(Street)
	 */
	public void updateStreet(Street street) {
		createAndUpdateStreet(street);
	}

	/**
	 * @see StreetDAO#deleteStreet(int)
	 */
	public void deleteStreet(int id) {
		Element rootElement = indexXMLInstance.getRootElement();
		Iterator<Element> it = rootElement.getChild("streets").getChildren().iterator();

		while (it.hasNext()) {
			Element street = it.next();
			int streetId = Integer.parseInt(street.getChildText("id"));

			if (streetId == id) {
				it.remove();
				break;
			}
		}
		streets.remove(streets.get(id)); // TODO maybe we should better use
											// lists instead of maps
		storeXML();
	}

	/**
	 * @see StreetDAO#streetExists(int)
	 */
	public boolean streetExists(int id) {
		return streets.containsKey(id);
	}

	/**
	 * Creates a new or updates an existing street.
	 * 
	 * @param street
	 */
	private void createAndUpdateStreet(Street street) {
		Element newElement = new Element("street");

		newElement.addContent(new Element("id").setText(String.valueOf(street.getId())));
		newElement.addContent(new Element("capacity").setText(String.valueOf(street.getCapacity())));
		newElement.addContent(new Element("lanes"));

		List<Lane> laneList = new ArrayList<Lane>(street.getLanes().values());

		for (Lane lane : laneList) {
			Element laneElement = new Element("lane");
			laneElement.addContent(String.valueOf(lane.getId()));
			newElement.getChild("lanes").addContent(laneElement);
		}

		// if street exists and must be updated, delete the old street from xml
		if (streets.containsKey(street.getId())) {
			Element rootElement = indexXMLInstance.getRootElement();
			Element streetElements = rootElement.getChild("streets");

			List<Element> streetList = new ArrayList<Element>(streetElements.getChildren());

			for (Element exstStreet : streetList) {
				int id = Integer.parseInt(exstStreet.getChildText("id"));
				if (id == street.getId()) {
					streetElements.removeContent(exstStreet);
					rootElement.getChild("streets").addContent(newElement);
					streets.put(street.getId(), street);
					break;
				}
			}
		}
		storeXML();
	}

	/**
	 * Parses the streets.xml file.
	 * 
	 * @throws IOException
	 * @throws JDOMException
	 */
	private void parseXML() {
		streets = new HashMap<Integer, Street>();
		List<Lane> laneList = new ArrayList<Lane>(laneDAO.getLanes().values());
		Element rootElement = indexXMLInstance.getRootElement();
		Element streetsElement = rootElement.getChild("streets");

		List<Element> streetElementList = streetsElement.getChildren();

		for (Element streetElement : streetElementList) {
			HashMap<Integer, Lane> lanes = new HashMap<Integer, Lane>();
			int streetId = Integer.parseInt(streetElement.getChildText("id"));
			int capacity = Integer.parseInt(streetElement.getChildText("capacity"));

			Element lanesElement = streetElement.getChild("lanes");

			List<Element> lanesElementList = lanesElement.getChildren();

			for (Element laneElement : lanesElementList) {
				int laneId = Integer.parseInt(laneElement.getText());
				
				for (Lane lane : laneList) {
					if (lane.getId() == laneId) {
						lanes.put(laneId, lane);
					}
				}
			}
			Street street = new StreetImpl(streetId, capacity, lanes);
			streets.put(streetId, street);
		}
	}
}
